// Reporter.ts - 数据上报器
// @/utils/monitor/reporter/Reporter.ts

import { MonitorConfig, MonitorEvent } from '../MonitorTypes';
import { MonitorEventBus } from '../core/MonitorEventBus';
import { getPlatform } from '../utils/platform';

interface QueueItem {
  event: MonitorEvent;
  retries: number;
  timestamp: number;
}

/**
 * 数据上报器
 * 负责收集监控事件并批量上报到服务器
 */
export class Reporter {
  private config: MonitorConfig;
  private eventBus: MonitorEventBus;
  private queue: QueueItem[] = [];
  private timer: any = null;
  private sending: boolean = false;
  private offlineQueue: MonitorEvent[] = [];
  private isStarted: boolean = false;

  constructor(config: MonitorConfig, eventBus: MonitorEventBus) {
    this.config = config;
    this.eventBus = eventBus;
  }

  /**
   * 启动上报器
   */
  public start(): void {
    if (this.isStarted) {
      return;
    }

    this.setupEventListener();
    this.setupTimer();
    this.setupOfflineHandler();
    this.isStarted = true;

    if (this.config.enableDebug) {
      console.log('[Reporter] Started data reporting');
    }
  }

  /**
   * 停止上报器
   */
  public stop(): void {
    if (!this.isStarted) {
      return;
    }

    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
    
    // 发送剩余数据
    this.flush(true);
    this.isStarted = false;

    if (this.config.enableDebug) {
      console.log('[Reporter] Stopped data reporting');
    }
  }

  /**
   * 设置事件监听器
   */
  private setupEventListener(): void {
    // 监听所有监控事件
    this.eventBus.on('*', (eventData: MonitorEvent) => {
      this.report(eventData);
    });
  }

  /**
   * 上报单个事件
   */
  public report(event: MonitorEvent): void {
    // 添加公共字段
    const enrichedEvent: MonitorEvent = {
      ...event,
      sessionId: this.getSessionId(),
      userId: this.config.userId,
      deviceId: this.getDeviceId(),
      platform: getPlatform(),
      userAgent: this.getUserAgent(),
      url: this.getCurrentUrl(),
      timestamp: event.timestamp || Date.now()
    };

    this.queue.push({
      event: enrichedEvent,
      retries: 0,
      timestamp: Date.now()
    });

    // 如果队列达到批量大小，立即发送
    if (this.queue.length >= (this.config.maxBatchSize || 10)) {
      this.flush();
    }
  }

  /**
   * 设置定时器
   */
  private setupTimer(): void {
    const flushInterval = this.config.flushInterval || 5000; // 默认5秒
    
    this.timer = setInterval(() => {
      if (this.queue.length > 0) {
        this.flush();
      }
    }, flushInterval);
  }

  /**
   * 设置离线处理
   */
  private setupOfflineHandler(): void {
    // #ifdef H5
    if (typeof window !== 'undefined') {
      // 监听网络状态
      const onlineHandler = () => {
        // 网络恢复，发送离线数据
        if (this.offlineQueue.length > 0) {
          const events = this.offlineQueue.splice(0);
          events.forEach(event => this.report(event));
          
          if (this.config.enableDebug) {
            console.log(`[Reporter] Sent ${events.length} offline events`);
          }
        }
      };

      const offlineHandler = () => {
        if (this.config.enableDebug) {
          console.log('[Reporter] Network offline, queueing events');
        }
      };

      window.addEventListener('online', onlineHandler);
      window.addEventListener('offline', offlineHandler);
    }
    // #endif

    // 小程序网络状态监听
    // #ifdef MP
    if (typeof uni !== 'undefined') {
      uni.onNetworkStatusChange?.((res: any) => {
        if (res.isConnected && this.offlineQueue.length > 0) {
          const events = this.offlineQueue.splice(0);
          events.forEach(event => this.report(event));
          
          if (this.config.enableDebug) {
            console.log(`[Reporter] Sent ${events.length} offline events`);
          }
        }
      });
    }
    // #endif
  }

  /**
   * 刷新队列，发送数据
   */
  public async flush(immediate: boolean = false): Promise<void> {
    if (this.sending || this.queue.length === 0) {
      return;
    }

    this.sending = true;
    
    try {
      // 取出要发送的数据
      const batchSize = this.config.maxBatchSize || 10;
      const items = this.queue.splice(0, batchSize);
      const events = items.map(item => item.event);

      // 检查网络状态
      const isOnline = await this.checkNetworkStatus();
      if (!isOnline) {
        this.offlineQueue.push(...events);
        if (this.config.enableDebug) {
          console.log(`[Reporter] Network offline, queued ${events.length} events`);
        }
        return;
      }

      // 准备发送数据
      const payload = {
        appId: this.config.appId,
        appVersion: this.config.appVersion,
        events,
        timestamp: Date.now(),
        ...this.config.metadata
      };

      // 发送数据
      const success = await this.sendData(payload, immediate);
      
      if (success) {
        if (this.config.enableDebug) {
          console.log(`[Reporter] Successfully sent ${events.length} events`);
        }
      } else {
        throw new Error('Send data failed');
      }
    } catch (error) {
      if (this.config.enableDebug) {
        console.error('[Reporter] Failed to send events:', error);
      }

      // 重试逻辑
      const batchSize = this.config.maxBatchSize || 10;
      const items = this.queue.splice(-batchSize, batchSize); // 恢复到队列末尾
      
      items.forEach(item => {
        const maxRetries = this.config.maxRetries || 3;
        if (item.retries < maxRetries) {
          item.retries++;
          this.queue.push(item);
        } else {
          // 超过最大重试次数，保存到离线队列
          this.offlineQueue.push(item.event);
          if (this.config.enableDebug) {
            console.warn('[Reporter] Event exceeded max retries, moved to offline queue');
          }
        }
      });
    } finally {
      this.sending = false;
    }
  }

  /**
   * 发送数据
   */
  private async sendData(payload: any, immediate: boolean = false): Promise<boolean> {
    const dataString = JSON.stringify(payload);
    
    // #ifdef H5
    if (typeof window !== 'undefined') {
      try {
        // 页面卸载时使用 sendBeacon
        if (immediate && navigator.sendBeacon) {
          const blob = new Blob([dataString], { type: 'application/json' });
          return navigator.sendBeacon(this.config.endpoint, blob);
        }
        
        // 正常情况使用 fetch
        if (typeof fetch !== 'undefined') {
          const response = await fetch(this.config.endpoint, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'X-Requested-With': 'XMLHttpRequest'
            },
            body: dataString,
            keepalive: immediate
          });

          return response.ok;
        }
        
        // 降级到 XMLHttpRequest
        return await this.sendWithXHR(dataString);
      } catch (error) {
        if (this.config.enableDebug) {
          console.error('[Reporter] H5 send failed:', error);
        }
        return false;
      }
    }
    // #endif

    // #ifdef MP
    // 小程序使用 uni.request
    if (typeof uni !== 'undefined') {
      return new Promise((resolve) => {
        uni.request({
          url: this.config.endpoint,
          method: 'POST',
          data: payload,
          header: {
            'Content-Type': 'application/json'
          },
          success: (res: any) => {
            resolve(res.statusCode >= 200 && res.statusCode < 300);
          },
          fail: (error: any) => {
            if (this.config.enableDebug) {
              console.error('[Reporter] Miniprogram send failed:', error);
            }
            resolve(false);
          }
        });
      });
    }
    // #endif

    return false;
  }

  /**
   * 使用XMLHttpRequest发送数据
   */
  private sendWithXHR(data: string): Promise<boolean> {
    return new Promise((resolve) => {
      try {
        const xhr = new XMLHttpRequest();
        xhr.open('POST', this.config.endpoint, true);
        xhr.setRequestHeader('Content-Type', 'application/json');
        
        xhr.onload = () => {
          resolve(xhr.status >= 200 && xhr.status < 300);
        };
        
        xhr.onerror = () => {
          resolve(false);
        };
        
        xhr.send(data);
      } catch (error) {
        resolve(false);
      }
    });
  }

  /**
   * 检查网络状态
   */
  private async checkNetworkStatus(): Promise<boolean> {
    // #ifdef H5
    if (typeof navigator !== 'undefined') {
      return navigator.onLine;
    }
    // #endif

    // #ifdef MP
    if (typeof uni !== 'undefined') {
      try {
        const result = await new Promise<boolean>((resolve) => {
          uni.getNetworkType({
            success: (res: any) => {
              resolve(res.networkType !== 'none');
            },
            fail: () => {
              resolve(true); // 默认认为有网络
            }
          });
        });
        return result;
      } catch (error) {
        return true; // 默认认为有网络
      }
    }
    // #endif

    return true; // 默认认为有网络
  }

  /**
   * 获取会话ID
   */
  private getSessionId(): string {
    // 可以从配置或全局状态获取
    return this.config.sessionId || 'anonymous-session';
  }

  /**
   * 获取设备ID
   */
  private getDeviceId(): string {
    // #ifdef H5
    if (typeof localStorage !== 'undefined') {
      let deviceId = localStorage.getItem('monitor_device_id');
      if (!deviceId) {
        deviceId = 'device_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
        localStorage.setItem('monitor_device_id', deviceId);
      }
      return deviceId;
    }
    // #endif

    // #ifdef MP
    if (typeof uni !== 'undefined') {
      try {
        let deviceId = uni.getStorageSync('monitor_device_id');
        if (!deviceId) {
          deviceId = 'device_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
          uni.setStorageSync('monitor_device_id', deviceId);
        }
        return deviceId;
      } catch (error) {
        return 'unknown_device';
      }
    }
    // #endif

    return 'unknown_device';
  }

  // getPlatform 函数已从 '../utils/platform' 模块导入

  /**
   * 获取用户代理
   */
  private getUserAgent(): string {
    // #ifdef H5
    if (typeof navigator !== 'undefined') {
      return navigator.userAgent;
    }
    // #endif

    // #ifdef MP
    if (typeof uni !== 'undefined') {
      const systemInfo = uni.getSystemInfoSync();
      return `${systemInfo.platform} ${systemInfo.system} ${systemInfo.version}`;
    }
    // #endif

    return 'unknown';
  }

  /**
   * 获取当前URL
   */
  private getCurrentUrl(): string {
    // #ifdef H5
    if (typeof window !== 'undefined') {
      return window.location.href;
    }
    // #endif

    // #ifdef MP
    if (typeof uni !== 'undefined') {
      const pages = getCurrentPages();
      if (pages.length > 0) {
        const currentPage = pages[pages.length - 1];
        return currentPage.route || 'unknown';
      }
    }
    // #endif

    return 'unknown';
  }

  /**
   * 获取队列状态
   */
  public getStatus(): {
    queueSize: number;
    offlineQueueSize: number;
    sending: boolean;
    isStarted: boolean;
  } {
    return {
      queueSize: this.queue.length,
      offlineQueueSize: this.offlineQueue.length,
      sending: this.sending,
      isStarted: this.isStarted
    };
  }

  /**
   * 清空队列
   */
  public clearQueue(): void {
    this.queue = [];
    this.offlineQueue = [];
    
    if (this.config.enableDebug) {
      console.log('[Reporter] Cleared all queues');
    }
  }
} 